package com.jbit.hxy.controller;

import cn.hutool.core.lang.Snowflake;
import cn.hutool.core.util.IdUtil;
import cn.hutool.extra.servlet.ServletUtil;
import com.github.binarywang.wxpay.bean.notify.WxPayNotifyResponse;
import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult;
import com.github.binarywang.wxpay.bean.notify.WxPayRefundNotifyResult;
import com.github.binarywang.wxpay.bean.order.WxPayMpOrderResult;
import com.github.binarywang.wxpay.bean.request.BaseWxPayRequest;
import com.github.binarywang.wxpay.bean.request.WxPayRefundRequest;
import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest;
import com.github.binarywang.wxpay.bean.result.WxPayOrderQueryResult;
import com.github.binarywang.wxpay.bean.result.WxPayRefundResult;
import com.github.binarywang.wxpay.bean.result.WxPayUnifiedOrderResult;
import com.github.binarywang.wxpay.constant.WxPayConstants;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.WxPayService;
import com.jbit.hxy.common.Result;
import com.jbit.hxy.feign.OrderFeignClient;
import com.jbit.hxy.model.dto.OrderPaymentDTO;
import com.jbit.hxy.model.dto.RefundDTO;
import com.jbit.hxy.model.po.WxOrder;
import com.jbit.hxy.model.po.WxPayInfo;
import com.jbit.hxy.properties.WxPayProperties;
import com.jbit.hxy.service.pay.WxPayInfoService;
import com.jbit.hxy.utils.IPUtils;
import com.jbit.hxy.utils.WxPayUtils;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;

import java.util.Objects;

@RestController
@RequestMapping("/wx")
@Tag(name = "微信支付")
@Slf4j
public class PaymentController {

    @Resource
    private WxPayInfoService wxPayInfoService;

    @Resource
    private WxPayProperties wxPayProperties;

    @Resource
    private WxPayService wxPayService;

    @Resource
    private OrderFeignClient orderFeignClient;

    @PostMapping("/prePay")
    public Result prePay(@RequestBody OrderPaymentDTO dto, HttpServletRequest request) {
        //RPC调用订单服务，获取订单信息
        Result<WxOrder> result = orderFeignClient.getOrderByOrderNumber(dto.getOrderNumber());
        WxOrder wxOrder = result.getData();
        if(Objects.isNull(wxOrder)){
            return Result.fail("此订单不存在！");
        }
        else if(! dto.getOpenId().equals(wxOrder.getOpenid())){
            return Result.fail("此订单非本人订单！");
        }

        // 微信支付请求参数
        WxPayUnifiedOrderRequest orderRequest = new WxPayUnifiedOrderRequest();
        // 随机字符串
        orderRequest.setNonceStr(WxPayUtils.generateNonceStr());
        // 订单流水号
        orderRequest.setOutTradeNo(wxOrder.getNumber());
        orderRequest.setTotalFee(1);//元转成分 BaseWxPayRequest.yuanToFen(wxOrder.getAmount().toString())
        //商品简单描述 "必填字段【[body]】必须提供值！"
        orderRequest.setBody("徽溪园");
        //交易类型 小程序取值如下：JSAPI
        orderRequest.setTradeType(WxPayConstants.TradeType.JSAPI);
        // 微信用户唯一标识 openid
        orderRequest.setOpenid(dto.getOpenId());
        //异步支付通知地址
        orderRequest.setNotifyUrl(wxPayProperties.getNotifyUrl());
        // 签名类型  MD5/HMAC-SHA256
        orderRequest.setSignType(WxPayConstants.SignType.MD5);
        // 终端IP
        orderRequest.setSpbillCreateIp(IPUtils.getIpAddr(request));
        try {
            Object preOrder = wxPayService.createOrder(orderRequest);
            System.out.println("获取Class对象：" + preOrder.getClass().getName());
            // 返回预支付交易单   uni.requestPayment() 发起支付
            return Result.success(preOrder);
        }catch (WxPayException ex) {
            return Result.fail(ex.getErrCodeDes()); //错误详情
        }
    }

    /*

     主动查询订单状态，客户是否已支付

     1、NOTPAY和订单未支付
     2、SUCCESS和支付成功   更新订单状态为支付成功
 */
    // loading 支付结果正在查询中，请稍后...
    @PostMapping("/orderQuery")
    public Result orderQuery(@RequestParam("outTradeNo") String outTradeNo)  {
        try {
            final WxPayOrderQueryResult result = wxPayService.queryOrder(null, outTradeNo);
            if ("SUCCESS".equals(result.getReturnCode())
                    && "SUCCESS".equals(result.getResultCode()) && "SUCCESS".equals(result.getTradeState())) {
                // TODO: 支付成功，更新订单状态：支付成功,添加交易记录
                log.info("交易类型:" + result.getTradeType());
                log.info("交易状态:" + result.getTradeState());
                log.info("订单总金额，单位为分:" + result.getTotalFee());
                log.info("微信支付订单号:" + result.getTransactionId());
                log.info("商户订单号:" + result.getOutTradeNo());
                log.info("支付完成时间:" + result.getTimeEnd());
                log.info("交易状态描述:" + result.getTradeStateDesc());
                log.info("openid:" + result.getOpenid());
                return Result.success(result);
            } else {
                /*
                "<xml><return_code><![CDATA[SUCCESS]]></return_code>
<return_msg><![CDATA[OK]]></return_msg>
<result_code><![CDATA[SUCCESS]]></result_code>
<mch_id><![CDATA[1527006801]]></mch_id>
<appid><![CDATA[wxe4248b4dff61ddf3]]></appid>
<device_info><![CDATA[]]></device_info>
<trade_state><![CDATA[NOTPAY]]></trade_state> 重要数据
<total_fee>1200</total_fee>
<out_trade_no><![CDATA[1834494291473469440]]></out_trade_no>
<trade_state_desc><![CDATA[订单未支付]]></trade_state_desc>  重要数据
<nonce_str><![CDATA[ERk2oLku7j5nBYcU]]></nonce_str>
<sign><![CDATA[A934207F38261656DC56E92696CE4529]]></sign>
</xml>"
                 */
                return Result.success(result);
            }
        }
        catch (WxPayException ex) {
            return Result.error(ex.getErrCodeDes()); //错误详情
        }

    }


    @Operation(summary = "支付结果通知,前端无需调用")
    @PostMapping("/notify")
    public String payNotify(@RequestBody String xmlData) {
        try {
            final WxPayOrderNotifyResult notifyResult = wxPayService.parseOrderNotifyResult(xmlData);
            if ("SUCCESS".equals(notifyResult.getReturnCode())) {
                //TODO: 添加支付记录和修改订单状态


                //WxJava SDK提供的WxPayNotifyResponse
                //SUCCESS表示商户接收通知成功并校验成功
                return WxPayNotifyResponse.success("OK");
            } else {
                return WxPayNotifyResponse.failResp("FAIL");
            }
        } catch (WxPayException e) {
            e.printStackTrace();
            return WxPayNotifyResponse.fail(e.getErrCodeDes());
        }
    }

    @Operation(summary = "申请退款")
    @PostMapping("/applyRefund")
    public Result applyQuickRefund(@RequestBody RefundDTO dto){
        // 通过订单号查询数据库获取订单信息
        Result<WxOrder> result = orderFeignClient.getOrderByOrderNumber(dto.getOutTradeNo());
        WxOrder wxOrder = result.getData();
        if(Objects.isNull(wxOrder)){
            return Result.fail("此订单不存在！");
        }
        else if(! dto.getOpenId().equals(wxOrder.getOpenid())){
            return Result.fail("此订单非本人订单！");
        }
        // 设置订单金额为数据库中的金额
        //dto.setTotalFee(wxOrder.getAmount());
        WxPayRefundRequest wxPayRefundRequest = new WxPayRefundRequest();
        Snowflake snowflake = IdUtil.getSnowflake(1, 1);

        dto.setOutRefundNo(snowflake.nextIdStr()); //商户退款单号(商户系统内部的退款单号)
        //dto.setRefundDesc("不想要了");

        //封装申请退款的请求参数

        //微信支付订单号
        wxPayRefundRequest.setTransactionId(dto.getTransactionId());
        // 商户退款单号
        wxPayRefundRequest.setOutRefundNo(dto.getOutRefundNo());
        // 商户订单号
        wxPayRefundRequest.setOutTradeNo(dto.getOutTradeNo());
        //订单金额
        wxPayRefundRequest.setTotalFee(dto.getTotalFee().intValue());
        //退款金额
        wxPayRefundRequest.setRefundFee(dto.getTotalFee().intValue());
        wxPayRefundRequest.setRefundDesc(dto.getRefundDesc()); //退款原因
        // 退款资金来源(未结算资金退款（默认使用未结算资金退款)
        wxPayRefundRequest.setRefundAccount(WxPayConstants.RefundAccountSource.UNSETTLED_FUNDS);
        // 退款结果通知url(异步接收微信支付退款结果通知的回调地址，通知URL必须为外网可访问的url，不允许带参数)
        wxPayRefundRequest.setNotifyUrl(wxPayProperties.getRefundUrl());

        try {
            WxPayRefundResult returnMap = wxPayService.refundV2(wxPayRefundRequest);
            if ("SUCCESS".equals(returnMap.getReturnCode())
                    && "SUCCESS".equals(returnMap.getResultCode())) {
                // TODO:修改订单状态为退款中
                return Result.success("退款申请接收成功！");
            }
            return Result.fail("退款申请失败");
        } catch (WxPayException ex) {
            ex.printStackTrace();
            return Result.error(ex.getErrCodeDes());
        }
    }

    @Operation(summary = "退款结果通知,前端无需调用")
    @PostMapping("/refundNotify")
    public String refundNotify(@RequestBody String xmlData){
        try {
            log.info("进入微信退款回调{}", xmlData);
            WxPayRefundNotifyResult result = wxPayService.parseRefundNotifyResult(xmlData);
            String outRefundNo = result.getReqInfo().getOutRefundNo();
            String transactionId = result.getReqInfo().getTransactionId();

            log.info("退款回调结果:{}", result);
            log.info("transactionId:{},outRefundNo:{}", transactionId,outRefundNo);

            if ("SUCCESS".equals(result.getReqInfo().getRefundStatus())) {
                // TODO:修改订单状态为退款成功

                return WxPayNotifyResponse.success("OK");
            } else {
                // TODO: 修改订单状态为退款失败

                return WxPayNotifyResponse.failResp("FAIL");
            }
        } catch (WxPayException e) {
            e.printStackTrace();
            log.error("退款回调异常,异常原因{}", e.getMessage());
            return WxPayNotifyResponse.fail(e.getErrCodeDes());
        }
    }
}
